/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using FullTextFactory = System.Qizx.Api.FullText.FullTextFactory;
using Scorer = System.Qizx.Api.FullText.Scorer;
namespace System.Qizx.Queries.Iterators
{
	
	/// <summary> Returns one dummy hit if 'counted' iterator verifies the count constraints.
	/// <p>
	/// Predicate iterator, can only be used by ContainerIter. NOT meant for
	/// actually iterating.
	/// </summary>
	public class CountIterator:PostingIteratorBase
	{
		protected internal PostingIterator counted;
		protected internal int min, max;
		protected internal bool docHasHits; // true if requested doc has hits
		
		/// <param name="max">if < 0 : no max
		/// </param>
		public CountIterator(int min, int max, PostingIterator counted)
		{
			this.counted = counted;
			this.min = min;
			this.max = max;
		}
		
		public override PostingIterator bornAgain()
		{
			return new CountIterator(min, max, counted.bornAgain());
		}
		
		public override bool skipToDoc(int docId)
		{
			bool ok = counted.skipToDoc(docId);
			curDocId = counted.DocId;
			// it is not always a failure if no more hits
			docHasHits = ok && (curDocId == docId);
			// This a bit of a hack: even though no hits in this doc, we use it 
			// anyway because this iterator can be used to implement ftnot...
			if (!docHasHits)
			{
				changeDoc(docId);
			}
			return true;
		}
		
		public override void  resetToNode(int nodeId)
		{
			counted.resetToNode(nodeId);
		}
		
		// useful?
		protected internal override bool basicSkipToNode(int nodeId, int limit)
		{
			return inRange(nodeId, System.Qizx.Queries.Iterators.PostingIterator_Fields.MAX_NODEID);
		}
		
		public override bool inRange(int rangeStart, int rangeEnd)
		{
			int count = counted.inRange(rangeStart, rangeEnd)?1:0;
			
			// test count for 'ftnot' or 'not empty'
			if (max > 0 && count > max || count == 0 && min > 0)
				return false;
			// take first occurrence of 'counted' as position
			if (count > 0)
				curNodeId = counted.NodeId;
			
			// decision can be made with this number of occurrences:
			int neededCount = (max < 0)?min:(max + 1);
			for (; count < neededCount && counted.nextBefore(rangeEnd); )
			{
				if (count == 0)
					curNodeId = counted.NodeId;
				++count;
			}
			
			if (count >= min && (max < 0 || count <= max))
			{
				return true;
			}
			return false;
		}
		
		public override void  initContainer(ContainerIterator container, FullTextFactory scoringFactory)
		{
			counted.initContainer(container, scoringFactory);
		}
		
		//    public boolean checkDepths(PostingIterator container)
		//    {
		//        return counted.checkDepths(container);
		//    }

        public override bool checkWordDistance(int/*NId*/ posting1, int/*NId*/ posting2,
                                     int offset, int min, int max)
		{
            return counted.checkWordDistance(posting1, posting2, offset, min, max);
		}
		
		public override bool checkBoundary(int posting, int boundary, bool start)
		{
			return counted.checkBoundary(posting, boundary, start);
		}
		
		public override float computeWeighting(Scorer scorer)
		{
			return counted.computeWeighting(scorer);
		}
		
		public override float computeScore(Scorer scorer)
		{
			return counted.computeScore(scorer);
		}
	}
}